package microcredit.gui.handler;

import java.awt.Component;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import microcredit.gui.selector.IFilter;

public abstract class AbstractHandlerWrapper<E, F> extends AbstractHandler<E>{

	private final AbstractHandler<F> delegate;
	
	public AbstractHandlerWrapper(AbstractHandler<F> delegate) {
		this.delegate = delegate;
	}
	
	protected abstract E convertTo(F o);
	
	protected abstract F convertFrom(E o);
	
	@Override
	public List<IFilter<E>> getFilters() {
		List<IFilter<F>> delegateFilters = delegate.getFilters();
		List<IFilter<E>> filters = new ArrayList<IFilter<E>>();
		for (final IFilter<F> delegateFilter : delegateFilters) {
			filters.add(new IFilter<E>() {
				@Override
				public String getLabel() {
					return delegateFilter.getLabel();
				}
				@Override
				public List<? extends Object> getValues() {
					return delegateFilter.getValues();
				}
				
				@Override
				public Object getSelectedValue() {
					return null;
				}
				
				@Override
				public void filter(Object exp, List<E> entities) {
					List<F> converted = new ArrayList<F>(entities.size());
					for (Iterator<E> iterator = entities.iterator(); iterator.hasNext();) {
						E e = iterator.next();
						converted.add(convertFrom(e));
					}
					delegateFilter.filter(exp, converted);
					if (converted.size() != entities.size()) {
						entities.removeAll(entities);
						for (F f : converted) {
							entities.add(convertTo(f));
						}
					}
				}
			});
		}
		return filters;
	}
	
	public E open(java.awt.Component component, E e) throws Throwable {
		return convertTo(delegate.open(component, convertFrom(e)));
	};
	
	@Override
	public void choose() throws Throwable {
		delegate.choose();
	}
	@Override
	public E newEntity(Component parent) throws Throwable {
		return convertTo(delegate.newEntity(parent));
	}
	
	public void delete(E e) throws Throwable {
		delegate.delete(convertFrom(e));
	};
	
	public E save(E entity) throws Throwable {
		return convertTo(delegate.save(convertFrom(entity)));
	};
	public E refresh(E element) throws Throwable {
		return convertTo(delegate.refresh(convertFrom(element)));
	};
	
	
	
	@Override
	public List<E> load() throws Throwable {
		List<E> list = new ArrayList<E>();
		List<F> delegates = delegate.load();
		for (F f : delegates) {
			list.add(convertTo(f));
		}
		return list;
	}
	
	@Override
	public List<E> select(List<E> entity) {
		List<F> list = new ArrayList<F>();
		for (E e : entity) {
			list.add(convertFrom(e));
		}
		list = delegate.select(list);
		List<E> l = new ArrayList<E>();
		for (F f : list) {
			l.add(convertTo(f));
		}
		return l;
	}
	
	public AbstractHandler<F> getDelegate() {
		return delegate;
	}
	
}
